<template>
  <div style="border: 1px solid #ccc">
    <div style="display: flex; align-items: center; border-bottom: 1px solid #ccc">
      <Toolbar style="border-bottom: 0; flex-shrink: 0" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
      <button style="margin-left: 10px; padding: 4px 8px" @click="exportToWord">导出为Word</button>
    </div>
    <Editor style="height: 500px; overflow-y: hidden;" :modelValue="modelValue" :defaultConfig="editorConfig"
      :mode="mode" @onCreated="handleCreated" @onChange="handleChange" @onDestroyed="handleDestroyed"
      @onFocus="handleFocus" @onBlur="handleBlur" @customAlert="customAlert" @customPaste="customPaste" />
  </div>
</template>
<script setup>
  import '@wangeditor/editor/dist/css/style.css' // 引入 css

  import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
  import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
  import { saveAs } from "file-saver";


  const props = defineProps({
    modelValue: {
      type: String,
      default: ''
    },
    placeholder: {
      type: String,
      default: '请输入内容...'
    }
  });
  const emits = defineEmits(['update:modelValue']);
  // 编辑器实例，必须用 shallowRef
  const editorRef = shallowRef()


  // 模拟 ajax 异步获取内容
  onMounted(() => {

  })

  const toolbarConfig = {}
  const editorConfig = { placeholder: props.placeholder, htmlTags: true }

  // 组件销毁时，也及时销毁编辑器
  onBeforeUnmount(() => {
    const editor = editorRef.value
    if (editor == null) return
    editor.destroy()
  })

  const handleCreated = (editor) => {
    editorRef.value = editor // 记录 editor 实例，重要！
  }
  const handleChange = (editor) => {
    const html = editor.getHtml() // 获取编辑器内容的HTML
    emits('update:modelValue', html) // 触发更新父组件的modelValue
    console.log('change:', editor.children)
  }
  const handleDestroyed = (editor) => {
    console.log('destroyed', editor)
  }
  const handleFocus = (editor) => {
    console.log('focus', editor)
  }
  const handleBlur = (editor) => {
    console.log('blur', editor)
  }
  const customAlert = (info, type) => {
    alert(`【自定义提示】${type} - ${info}`)
  }
  const customPaste = (editor, event, callback) => {
    console.log('ClipboardEvent 粘贴事件对象', event)
    // const html = event.clipboardData.getData('text/html') // 获取粘贴的 html
    // const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
    // const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据（如从 word wsp 复制粘贴）

    // 自定义插入内容
    editor.insertText('xxx')

    // 返回 false ，阻止默认粘贴行为
    event.preventDefault()
    callback(false) // 返回值（注意，vue 事件的返回值，不能用 return）

    // 返回 true ，继续默认的粘贴行为
    // callback(true)
  }

  const exportToWord = async () => {
    const editor = editorRef.value;
    if (!editor) {
      customAlert('编辑器未初始化，无法导出', 'warning');
      return;
    }

    const html = editor.getHtml();
    if (!html) {
      customAlert('编辑器内容为空，无法导出', 'warning');
      return;
    }
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = html;
    tempDiv.id = 'editor-content';

    Array.from(tempDiv.querySelectorAll('*')).forEach(item => {
      if (item.tagName === 'TABLE') {
        const table = convertElTableToHtmlTableWord(item.childNodes[0], '');
        item.innerHTML = table;
      }
    })

    const regularImages = Array.from(tempDiv.querySelectorAll('img'));//提取图片
    const imagePromises = regularImages.map(imgElement => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      const imgObj = new Image();
  
      imgObj.crossOrigin = 'Anonymous'; // 如果图片需要跨域访问的，必写，不然会报错
      imgObj.src = imgElement.src;
  
      return new Promise((resolve, reject) => {
        imgObj.onload = () => {
          //canvas宽高：如果页面上img设置了style="width:50px;height:50px"，已页面设置的为主，如果没有设置就是默认图片的大小
          canvas.width = imgElement.width || imgObj.width;// 想要的canvas固定宽度
          canvas.height = imgElement.height || imgObj.height;// 想要的canvas固定高度
          console.log('width', imgElement.width, imgObj.width, 'height', imgElement.height, imgObj.height);
          //在canvas里面绘制图片：图片的宽高需要按缩放比例进行绘制
          //计算缩放比例
          var ratio = Math.min(canvas.width / imgObj.width, canvas.height / imgObj.height);
          var scaledWidth = imgObj.width * ratio;
          var scaledHeight = imgObj.height * ratio;
          var offsetX = (canvas.width - scaledWidth) / 2;
          var offsetY = (canvas.height - scaledHeight) / 2;
          // console.log(ratio,scaledWidth,scaledHeight, offsetX, offsetY);
          // 绘制缩小后的图片
          ctx.drawImage(imgObj, 0, 0, imgObj.width, imgObj.height, offsetX, offsetY, scaledWidth, scaledHeight);
          // 将缩小后的图片导出为PNG
          resolve(canvas.toDataURL('image/png'));
        };
        imgObj.onerror = reject;
      }).catch(e => {
        console.log('e', e);
      });
    })

    Promise.all(imagePromises).then(imgUrls => {
      imgUrls.forEach((imgUrl, i) => {
        regularImages[i].src = imgUrl;
      });
      // 构建包含 HTML 内容的完整 HTML 文档字符串
      const fullHtmlContent = `
        <!DOCTYPE html>
        <html>
          <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          </head>
          <body>
            ${tempDiv.outerHTML}
          </body>
        </html>
      `;
      const blob = htmlDocx.asBlob(fullHtmlContent);
      saveAs(blob, 'editor-content.docx');
    });

    
  }
  // 处理table转换为html
function convertElTableToHtmlTableWord(elTable, title, infoLeft = '', infoRight = '') {
  if (!elTable) return '';
  console.log('elTable', elTable);
  // 获取 el-table 的表头数据，包括多级表头
  const theadRows = elTable.querySelectorAll('thead tr');
  // 获取 el-table 的数据行
  const tbodyRows = elTable.querySelectorAll('tbody tr');
  let length = 0;
  if (theadRows.length != 0) {
    length = getTotalColumnCount(theadRows[0]);
  };
  // 开始构建 HTML 表格的字符串，设置表格整体样式和边框样式
  let htmlTable = '<table style="width:100%;border-collapse: collapse;border-spacing: 0;mso-border-alt: none;" cellspacing="0;" cellpadding="0;">';
  if(length > 0) {
    htmlTable += '<thead><tr>';
    if (infoRight != '') {
      htmlTable += `<th colspan="${Math.floor(length / 2)}" style="width:306.2000pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid rgb(255,255,255);
  mso-border-left-alt:0.5000pt solid rgb(255,255,255);border-right:1.0000pt solid rgb(255,255,255);mso-border-right-alt:0.5000pt solid rgb(255,255,255);
  border-top:1.0000pt solid rgb(255,255,255);mso-border-top-alt:0.5000pt solid rgb(255,255,255);border-bottom:none;
  mso-border-bottom-alt:none;background:rgb(255,255,255);text-align: right;">单位:${infoRight}</th>`;
    } else {
      htmlTable += `<th colspan="${Math.floor(length / 2)}" style="width:306.2000pt;padding:0.0000pt 5.4000pt 0.0000pt 5.4000pt ;border-left:1.0000pt solid rgb(255,255,255);
  mso-border-left-alt:0.5000pt solid rgb(255,255,255);border-right:1.0000pt solid rgb(255,255,255);mso-border-right-alt:0.5000pt solid rgb(255,255,255);
  border-top:1.0000pt solid rgb(255,255,255);mso-border-top-alt:0.5000pt solid rgb(255,255,255);border-bottom:none;
  mso-border-bottom-alt:none;background:rgb(255,255,255);text-align: right;"></th>`;
    }
    htmlTable += '</tr>';

    // 处理多级表头
    theadRows.forEach(row => {
      htmlTable += '<tr>';
      const columns = row.querySelectorAll('th');
      columns.forEach(column => {
        const colspan = column.getAttribute('colspan') || '1';
        const rowspan = column.getAttribute('rowspan') || '1';
        htmlTable += `<th colspan="${colspan}" rowspan="${rowspan}" style="border: 1px solid black;">${column.innerText}</th>`;
      });
      htmlTable += '</tr>';
    });
    theadRows.forEach(row => {
      htmlTable += '<tr>';
      const columns = row.querySelectorAll('th');
      columns.forEach(column => {
        const colspan = column.getAttribute('colspan') || '1';
        const rowspan = column.getAttribute('rowspan') || '1';
        htmlTable += `<th colspan="${colspan}" rowspan="${rowspan}" style="border: 1px solid black;">${column.innerText}</th>`;
      });
      htmlTable += '</tr>';
    });

    htmlTable += '</thead>';
  }
  htmlTable += '<tbody>';
  // 构建数据行, 如果标题在tbody中
  tbodyRows.forEach(row => {
    htmlTable += '<tr>';
    const cells = row.querySelectorAll('th');
    
    cells.forEach(cell => {
      let spans = cell.querySelector('*')
      if (spans) {
        // 如果spans有子元素，获取子元素中的style
        let style = spans.getAttribute('style');
        // 如果style有值，将其添加到th标签中
        // if (style) {
        //   htmlTable += `<th style="border: 1px solid black;${style}">${cell.innerText}</th>`;  
        // }
        htmlTable += `<th style="padding:0;border: 1px solid black;${style}" colspan="0" rowspan="0">${cell.querySelector('span').innerHTML}</th>`;
      } else {
        htmlTable += `<th style="padding:0;border: 1px solid black;"  colspan="0" rowspan="0">${cell.innerText}</th>`;
      }
    });
    htmlTable += '</tr>';
  });
  // 构建数据行
  tbodyRows.forEach(row => {
    htmlTable += '<tr>';
    const cells = row.querySelectorAll('td');
    cells.forEach(cell => {
      if (cell.querySelector('div')) {
        htmlTable += `<td style="padding:0;border: 1px solid black;line-height: 1.5;min-width: 30px;padding: 3px 5px;text-align: left;" colspan="0" rowspan="0">${cell.querySelector('div').innerHTML}</td>`;
      } else {
        htmlTable += `<td style="padding:0;border: 1px solid black;line-height: 1.5;min-width: 30px;padding: 3px 5px;text-align: left;" colspan="0" rowspan="0">${cell.innerText}</td>`;
      }
    });
    htmlTable += '</tr>';
  });
 

  htmlTable += '</tbody></table>';
  return htmlTable;
}
//获取总列数
function getTotalColumnCount(theadRows) {
  let rowColumns = 0;
  const columns = theadRows.querySelectorAll('th');
  columns.forEach(column => {
    const colspan = column.getAttribute('colspan') || 1;
    rowColumns += Number(colspan);
  });
  return rowColumns;
}
</script>